/*--------------------------------------------------------------------------
    This source file is part of Abraxas Game Engine
    For the latest info, see http://code.google.com/abraxasge/
    Copyright (C) 2009, Andrew LeRoy <aleroy@member.igda.org>
    ---

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA  02110-1301, USA.
--------------------------------------------------------------------------*/
#ifndef _Abx_Log_hpp_
#define _Abx_Log_hpp_

#include "AbxPrerequisites.hpp"
#include "AbxString.hpp"

namespace Abx
{
    enum LogDest
    {
        LOG_DEST_DEFAULT    = 0x11,
        LOG_DEST_FILE       = 0x01,
        LOG_DEST_CONSOLE    = 0x10
    };
    
    enum LogLevel
    {
        LOG_LVL_DEFAULT     = 0,
        LOG_LVL_BRIEF       = 1,
        LOG_LVL_NORMAL      = 2,
        LOG_LVL_VERBOSE     = 3
    };
    
    enum LogEntryType
    {
        LOG_ENTRY_DEFAULT   = 0x1111,
        LOG_ENTRY_MESSAGE   = 0x0001,
        LOG_ENTRY_WARNING   = 0x0010,
        LOG_ENTRY_ERROR     = 0x0100,
        LOG_ENTRY_DEBUG     = 0x1000
    };
    
    
    class _AbxExport Log
    {
      public:
        class Stream;
        
        Log(String const& name, LogDest writeTo, LogLevel level, LogEntryType entryTypes);
        ~Log();
        
        String const& getName() const           { return mName;                      };
        
        bool willWriteToFile() const            { return (mDest & LOG_DEST_FILE);    };
        bool willWriteToConsole() const         { return (mDest & LOG_DEST_CONSOLE); };
        
        LogLevel getLogLevel() const                   { return mLevel;             };
        void setLogLevel(LogLevel lvl)                 { mLevel = lvl;              };
        LogEntryType getLogEntryType() const            { return mEntry;             };
        void setLogEntryTypes(LogEntryType entryTypes) { mEntry = entryTypes;       };
        
        void logMessage(String const& message, LogEntryType entryType=LOG_ENTRY_MESSAGE);
        Stream stream(LogEntryType entryType=LOG_ENTRY_MESSAGE);
        
      private:
        std::ofstream   mfpLog;
        String const    mName;
        LogDest const   mDest;
        LogLevel        mLevel;
        LogEntryType    mEntry;
        
      public:
        class Stream
        {
          public:
            /// Simple type to indicate a flush of the stream to the log
            struct Flush {};

            Stream(Log* target, LogEntryType entryType)
                :mTarget(target), mEntry(entryType)
            { }
            // copy constructor
            Stream(const Stream& rhs) 
                : mTarget(rhs.mTarget), mEntry(rhs.mEntry)
            {
                // explicit copy of stream required, gcc doesn't like implicit
                mCache.str(rhs.mCache.str());
            } 
            ~Stream()
            {
                // flush on destroy
                if (mCache.tellp() > 0)
                {
                    mTarget->logMessage(mCache.str(), mEntry);
                }
            }

            template <typename T>
            Stream& operator<< (const T& v)
            {
                mCache << v;
                return *this;
            }

            Stream& operator<< (const Flush& v)
            {
                mTarget->logMessage(mCache.str(), mEntry);
                mCache.str(StringTools::BLANK);
                return *this;
            }
           
          protected:
            Log*            mTarget;
            LogEntryType    mEntry;
            
            typedef StringTools::StrStreamType BaseStream;
            BaseStream      mCache;            
        }; // class Stream
    }; // class Log
} // namespace Abx

#endif // _Abx_Log_hpp_
